#include "VSAnimBlendFunction.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI_NoCreateFun(VSAnimBlendFunction,VSAnimFunction)
VSAnimBlendFunction::VSAnimBlendFunction()
{
	m_uiCrossFadingType = CFT_SMOOTH;
	m_NodeCrossFadingTime.Clear();
	m_fCrossFadingTime = 0.0f;
	m_uiLastAnimIndex = VSMAX_INTEGER;
}
VSAnimBlendFunction::VSAnimBlendFunction(const VSUsedName & ShowName,VSAnimTree * pAnimTree)
:VSAnimFunction(ShowName,pAnimTree)
{
	m_uiCrossFadingType = CFT_SMOOTH;
	m_NodeCrossFadingTime.Clear();
	m_fCrossFadingTime = 0.0f;
	m_uiLastAnimIndex = VSMAX_INTEGER;

	VSString OutputName = _T("Output");
	VSOutputNode * pOutputNode = NULL;
	pOutputNode = VS_NEW VSOutputNode(VSPutNode::AVT_ANIM,OutputName,this);
	VSMAC_ASSERT(pOutputNode);
	m_pOutput.AddElement(pOutputNode);

	

}
VSAnimBlendFunction::~VSAnimBlendFunction()
{
	
}
bool VSAnimBlendFunction::UpdateEx(double dAppTime)
{
	if (!VSAnimFunction::UpdateEx(dAppTime))
	{
		return 0;

	}
	if(!ComputePara(dAppTime))
		return 0;
	if(!ComputeOutBoneMatrix(dAppTime))
		return 0;
	return 1;
}
void VSAnimBlendFunction::LineBlendTwo(VSAnimFunction * pOut,
									   VSAnimFunction * pAnimFunction1,VSAnimFunction * pAnimFunction2,
									   VSREAL fWeight)
{
	if (!pOut || fWeight < 0.0f || fWeight > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->m_BoneOutPut.GetNum();
	if (!uiBoneNum)
	{
		return ;
	}
	
	if (pAnimFunction1 && pAnimFunction2)
	{

		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i].Interpolation(pAnimFunction1->m_BoneOutPut[i],pAnimFunction2->m_BoneOutPut[i],fWeight);
		}
	}
	else if (pAnimFunction1)
	{
		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction1->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction2)
	{
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction2->m_BoneOutPut[i];
		}
	}
}
void VSAnimBlendFunction::LineBlendThree(VSAnimFunction * pOut,
						VSAnimFunction * pAnimFunction1,VSAnimFunction * pAnimFunction2,VSAnimFunction * pAnimFunction3,
						   VSREAL fWeight1,VSREAL fWeight2)
{
	if (!pOut || fWeight1 < 0.0f || fWeight2 < 0.0f || fWeight1 + fWeight2 > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->m_BoneOutPut.GetNum();
	if (!uiBoneNum)
	{
		return ;
	}

	if (pAnimFunction1 && pAnimFunction2 && pAnimFunction3)
	{

		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction3->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction1->m_BoneOutPut[i] * fWeight1 
									+ pAnimFunction2->m_BoneOutPut[i] * fWeight2 
									+ pAnimFunction3->m_BoneOutPut[i] * (1.0f - fWeight1 - fWeight2);
		}
	}
	else if (pAnimFunction1)
	{
		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction1->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction2)
	{
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction2->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction3)
	{
		if (uiBoneNum != pAnimFunction3->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			pOut->m_BoneOutPut[i] = pAnimFunction3->m_BoneOutPut[i];
		}
	}
}
void VSAnimBlendFunction::LineBlendTwo(VSArray<VSAnimAtom> *pOut,
						 const VSArray<VSAnimAtom> * pIn1,const VSArray<VSAnimAtom> *pIn2,
						 VSREAL fWeight)
{

	if (pOut || fWeight < 0.0f || fWeight > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->GetNum();
	if (!uiBoneNum)
	{
		return ;
	}

	if (pIn1 && pIn2)
	{

		if (uiBoneNum != pIn1->GetNum())
		{
			return ;
		}
		if (uiBoneNum != pIn2->GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i].Interpolation((*pIn1)[i],(*pIn2)[i],fWeight); 
		}
	}
	else if (pIn1)
	{
		if (uiBoneNum != pIn1->GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn1)[i];
		}
	}
	else if (pIn2)
	{
		if (uiBoneNum != pIn2->GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn2)[i];
		}
	}
}
void VSAnimBlendFunction::LineBlendThree(VSArray<VSAnimAtom> *pOut,
						   const VSArray<VSAnimAtom> * pIn1,const VSArray<VSAnimAtom> *pIn2,const VSArray<VSAnimAtom> *pIn3,
						   VSREAL fWeight1,VSREAL fWeight2)
{
	if (!pOut || fWeight1 < 0.0f || fWeight2 < 0.0f || fWeight1 + fWeight2 > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->GetNum();
	if (!uiBoneNum)
	{
		return ;
	}

	if (pIn1 && pIn2 && pIn3)
	{

		if (uiBoneNum != pIn1->GetNum())
		{
			return ;
		}
		if (uiBoneNum != pIn2->GetNum())
		{
			return ;
		}
		if (uiBoneNum != pIn3->GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn1)[i] * fWeight1 
				+ (*pIn2)[i] * fWeight2 
				+ (*pIn3)[i] * (1.0f - fWeight1 - fWeight2);
		}
	}
	else if (pIn1)
	{
		if (uiBoneNum != pIn1->GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn1)[i];
		}
	}
	else if (pIn2)
	{
		if (uiBoneNum != pIn2->GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn2)[i];
		}
	}
	else if (pIn3)
	{
		if (uiBoneNum != pIn3->GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = (*pIn3)[i];
		}
	}

}

void VSAnimBlendFunction::LineBlendTwo(VSArray<VSAnimAtom> *pOut,
									   VSAnimFunction * pAnimFunction1,VSAnimFunction * pAnimFunction2,
									   VSREAL fWeight)
{
	if (!pOut || fWeight < 0.0f || fWeight > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->GetNum();
	if (!uiBoneNum)
	{
		return ;
	}

	if (pAnimFunction1 && pAnimFunction2)
	{

		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i].Interpolation(pAnimFunction1->m_BoneOutPut[i],pAnimFunction2->m_BoneOutPut[i],fWeight);
		}
	}
	else if (pAnimFunction1)
	{
		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = pAnimFunction1->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction2)
	{
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = pAnimFunction2->m_BoneOutPut[i];
		}
	}
}
void VSAnimBlendFunction::LineBlendThree(VSArray<VSAnimAtom> *pOut,
										 VSAnimFunction * pAnimFunction1,VSAnimFunction * pAnimFunction2,VSAnimFunction * pAnimFunction3,
										 VSREAL fWeight1,VSREAL fWeight2)
{
	if (!pOut || fWeight1 < 0.0f || fWeight2 < 0.0f || fWeight1 + fWeight2 > 1.0f)
	{
		return ;
	}
	unsigned int uiBoneNum = pOut->GetNum();
	if (!uiBoneNum)
	{
		return ;
	}

	if (pAnimFunction1 && pAnimFunction2 && pAnimFunction3)
	{

		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}
		if (uiBoneNum != pAnimFunction3->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
// 			(*pOut)[i] = pAnimFunction1->m_BoneOutPut[i] * fWeight1 
// 				+ pAnimFunction2->m_BoneOutPut[i] * fWeight2 
// 				+ pAnimFunction3->m_BoneOutPut[i] * (1.0f - fWeight1 - fWeight2);
		}
	}
	else if (pAnimFunction1)
	{
		if (uiBoneNum != pAnimFunction1->m_BoneOutPut.GetNum())
		{
			return ;
		}

		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = pAnimFunction1->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction2)
	{
		if (uiBoneNum != pAnimFunction2->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = pAnimFunction2->m_BoneOutPut[i];
		}
	}
	else if (pAnimFunction3)
	{
		if (uiBoneNum != pAnimFunction3->m_BoneOutPut.GetNum())
		{
			return ;
		}


		for (unsigned int i = 0 ; i < uiBoneNum ;i++)
		{
			(*pOut)[i] = pAnimFunction3->m_BoneOutPut[i];
		}
	}
}
unsigned int VSAnimBlendFunction::DiskUse()const
{
	unsigned int Used = VSAnimFunction::DiskUse();

	Used += sizeof(unsigned int);
	unsigned int uiCrossFadingTimeNum = m_NodeCrossFadingTime.GetNum();

	Used += sizeof(unsigned int);
	Used += sizeof(VSREAL) * uiCrossFadingTimeNum;
	return Used;
}
bool VSAnimBlendFunction::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSAnimFunction::Save(rStream,iSaveUse))
		return 0;

	if(!rStream.Write(&m_uiCrossFadingType,sizeof(unsigned int )))
		return 0;
	iSaveUse += sizeof(unsigned int );

	unsigned int uiCrossFadingTimeNum = m_NodeCrossFadingTime.GetNum();

	if(!rStream.Write(&uiCrossFadingTimeNum,sizeof(unsigned int )))
		return 0;
	iSaveUse += sizeof(unsigned int );


	if(!rStream.Write(m_NodeCrossFadingTime.GetBuffer(),sizeof(VSREAL) * uiCrossFadingTimeNum))
		return 0;
	iSaveUse += sizeof(VSREAL) * uiCrossFadingTimeNum;
	return 1;
}
bool VSAnimBlendFunction::Load(VSStream & rStream,unsigned int &iSaveUse)
{	
	if(!VSAnimFunction::Load(rStream,iSaveUse))
		return 0;


	if(!rStream.Read(&m_uiCrossFadingType,sizeof(unsigned int )))
		return 0;
	iSaveUse += sizeof(unsigned int );

	unsigned int uiCrossFadingTimeNum = 0;

	if(!rStream.Read(&uiCrossFadingTimeNum,sizeof(unsigned int )))
		return 0;
	iSaveUse += sizeof(unsigned int );

	m_NodeCrossFadingTime.SetBufferNum(uiCrossFadingTimeNum);
	if(!rStream.Read(m_NodeCrossFadingTime.GetBuffer(),sizeof(VSREAL) * uiCrossFadingTimeNum))
		return 0;
	iSaveUse += sizeof(VSREAL) * uiCrossFadingTimeNum;
	return 1;
}

bool VSAnimBlendFunction::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSAnimBlendFunction* Temp = DynamicCast<VSAnimBlendFunction>(pObject); 
	if(!Temp)
		return 0;
	if(VSAnimFunction::Clone(pObject,uiType))
	{

		m_uiCrossFadingType = Temp->m_uiCrossFadingType;
		m_NodeCrossFadingTime = Temp->m_NodeCrossFadingTime;
		return 1;

	}
	else
	{
		return 0;
	}

}